/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.action.retrievedefault;

import com.inspur.edp.bef.api.action.assembler.IBEActionAssembler;
import com.inspur.edp.bef.api.be.IBEContext;
import com.inspur.edp.bef.api.be.IBENodeEntity;
import com.inspur.edp.bef.api.exceptions.BefException;
import com.inspur.edp.bef.api.exceptions.ErrorCodes;
import com.inspur.edp.bef.api.parameter.retrieve.RetrieveParam;
import com.inspur.edp.bef.core.action.AuthorityUtil;
import com.inspur.edp.bef.core.action.base.ActionUtil;
import com.inspur.edp.bef.core.be.BENodeEntity;
import com.inspur.edp.bef.core.be.BusinessEntity;
import com.inspur.edp.bef.core.be.CoreBEContext;
import com.inspur.edp.bef.core.lock.LockUtils;
import com.inspur.edp.bef.core.session.FuncSessionManager;
import com.inspur.edp.bef.entity.exception.ExceptionLevel;
import com.inspur.edp.bef.spi.action.AbstractAction;
import com.inspur.edp.bef.spi.entity.CodeRuleInfo;
import com.inspur.edp.bef.spi.entity.builtinimpls.BefEntityResInfoImpl;
import com.inspur.edp.bef.spi.entity.columnconfig.ColumnGenerateConfigLoader;
import com.inspur.edp.bef.spi.entity.columnconfig.ColumnGenerateInfo;
import com.inspur.edp.cdp.coderule.api.CodeRuleBEAssignService;
import com.inspur.edp.cef.entity.accessor.entity.IEntityAccessor;
import com.inspur.edp.cef.entity.changeset.AddChangeDetail;
import com.inspur.edp.cef.entity.changeset.ModifyChangeDetail;
import com.inspur.edp.cef.entity.entity.IChildEntityData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IEntityDataCollection;
import com.inspur.edp.cef.spi.entity.resourceInfo.EntityResInfo;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.util.StringUtils;

public class RetrieveDefaultChildAction extends AbstractAction<IEntityData>
{
		//region Constructor
	public RetrieveDefaultChildAction(List<String> nodeCodes, List<String> hierachyIdList,
			String dataID, Map<String, Object> defaultValues) {
		this.nodeCodes = nodeCodes;
		this.hierachyIdList = hierachyIdList;
		this.dataID = dataID;
		this.defaultValues = defaultValues;
	}

		//endregion

	private java.util.List<String> nodeCodes;
	private java.util.List<String> hierachyIdList;
	private String dataID;
	private Map<String, Object> defaultValues;
	private AddChangeDetail childChange;
	private String childId;
	private IEntityData data;

	@Override
	public void execute()
	{
		AuthorityUtil.checkDataAuthority((IBEContext)this.getBEContext());
		executeCore();
		setDefaultValue();
		executeDetermination();
		setResult();
	}

	private void executeCore()
	{
		childId = StringUtils.isEmpty(dataID) ? getColumnId() : dataID;
		LockUtils.checkLock((IBEContext)getBEContext());
		CoreBEContext beCtx = (CoreBEContext)getBEContext();
		ModifyChangeDetail rootChange = new ModifyChangeDetail(beCtx.getID());
		ModifyChangeDetail currChange = rootChange;
		IEntityDataCollection childCollection = beCtx.getCurrentData().getChilds().get(nodeCodes.get(0));
		for (int i = 1; i < nodeCodes.size(); i++)
		{
			final String currentId = hierachyIdList.get(i);
			ModifyChangeDetail childChange = new ModifyChangeDetail(currentId);
			currChange.addChildChangeSet(nodeCodes.get(i - 1), childChange);
			currChange = childChange;
			IEntityData childData = childCollection.stream()
					.filter(item -> item.getID().equals(currentId)).findFirst().orElse(null);
			if (childData == null) {
				throw new BefException(
						ErrorCodes.DeletingNonExistence, String
						.format("新增时上级数据不存在%1$s(%2$s)", currentId == null ? "" : currentId,
								nodeCodes.get(i - 1)), null, ExceptionLevel.Error);
			}
			childCollection = childData.getChilds().get(nodeCodes.get(i));
		}
		IBENodeEntity entity = getChildEntity();
		IEntityData childEntity = entity.createEntityData(childId);
		((IChildEntityData)childEntity).setParentID(((IBENodeEntity)entity.getParent()).getID());
		data = ((IBENodeEntity)entity.getParent()).createChildAccessor(nodeCodes.get(nodeCodes.size() - 1), childEntity);
		assignDefaultValue((BENodeEntity)entity, data);
		assignIntroducedValue(data);
		assignCode(data, (BENodeEntity) entity);
		((IChildEntityData)childEntity).setParentID(((IBENodeEntity)entity.getParent()).getID());
		childChange = new AddChangeDetail(data);
    currChange.addChildChangeSet(nodeCodes.get(nodeCodes.size() - 1), childChange);
		ActionUtil.getRootEntity(this).appendTempCurrentChange(rootChange);

	}

	private IBENodeEntity getChildEntity()
	{
		IBENodeEntity currentEntity = ActionUtil.getRootEntity(this);
		for (int i = 0; i < nodeCodes.size(); i++)
		{
			currentEntity = currentEntity.getChildBEEntity(nodeCodes.get(i),
				i == nodeCodes.size() - 1 ? childId : hierachyIdList.get(i + 1));
		}

		return currentEntity;
	}

	private void setDefaultValue()
	{
		IEntityAccessor accessor = (IEntityAccessor)data;
		RetrieveDefaultAction.getDefaultValueProcessor((IBEContext)getContext()).setValue(accessor.getNodeCode(), (IEntityData)accessor.getInnerData());
	}

	private void assignDefaultValue(BENodeEntity be, IEntityData data)
	{
		be.assignDefaultValue(data);
	}

	private void getParentData(BENodeEntity entity,ArrayList<String> nodeCodesTemp,HashMap<String,Object> map,int i)
	{
		if(i>nodeCodesTemp.size()-1)
			return ;
		map.put(nodeCodesTemp.get(i),entity.getParent().getData());

		getParentData((BENodeEntity) entity.getParent(),nodeCodesTemp,map,i+1);
	}

	private ArrayList<String> getReverseNocodes(List<String> source,BusinessEntity be){

		ArrayList<String> nodeCodesTemp=  new ArrayList<>();
		for(int i=source.size()-1; i>=0; i--){

			nodeCodesTemp.add(source.get(i));
		}
		//添加主表的节点编号
		nodeCodesTemp.add(be.getNodeCode());
		return  nodeCodesTemp;
	}
	private void assignCode(IEntityData data,BENodeEntity entity) {
		HashMap<String,Object> map=new HashMap<>();
		BusinessEntity be=ActionUtil.getRootEntity(this);

		ArrayList<String> reverseNodeCodes=getReverseNocodes(nodeCodes,be);
		//倒序之后，从第二个值开始遍历，给map赋值，
		getParentData(entity,reverseNodeCodes,map,1);

		map.put(nodeCodes.get(nodeCodes.size()-1),data);
		java.util.HashMap<String, CodeRuleInfo> codeInfo = entity.getAfterCreateCodeRule();
		if (codeInfo == null || codeInfo.isEmpty()) {
			return;
		}
		CodeRuleBEAssignService service = SpringBeanUtils.getBean(CodeRuleBEAssignService.class);
		for (String key : codeInfo.keySet())
		{
			String code = service.generate(
					be.getBEContext().getBEManagerContext().getBEManager().getBEInfo().getBEID(),
					nodeCodes.get(nodeCodes.size()-1),
					key,
					map,
					codeInfo.get(key).getCodeRuleId());
			data.setValue(key, code);
		}
	}

	private void assignIntroducedValue(IEntityData acc) {
		if (defaultValues == null || defaultValues.isEmpty()) {
			return;
		}

		IEntityData data = (IEntityData) ((IEntityAccessor) acc).getInnerData();
		String orgId = data.getID();

		for (Map.Entry<String, Object> pair : defaultValues.entrySet()) {
			data.setValue(pair.getKey(), pair.getValue());
		}
		if (!orgId.equals(data.getID())) {
			throw new IllegalArgumentException("默认值中不能包含主键");
		}
		((IEntityAccessor) acc).setInnerData(data);
	}

	private String getCode(String ruleId)
	{
		//TODO: java版临时注释 变量优先级低
		return null;
//		ICodeRuleService service = ServiceManager.<ICodeRuleService>GetService();
//		return service.generate(ruleId,null);
	}

	//调用retrieveDefault时机Determination
	private void executeDetermination()
	{
		getChildEntity().retrieveDefaultDeterminate();
		//ActionUtil.getRootEntity(this).executeAction(new ActionFactory().getRetrieveDefaultChildDtmAction(
		//    CoreBEContext.createDeterminationContext(), nodeCodes, Result, childChange));
	}

	private void setResult()
	{
		java.util.ArrayList<String> idList = new java.util.ArrayList<String>(hierachyIdList);
		idList.add(data.getID());
		RetrieveParam tempVar = new RetrieveParam();
		tempVar.setNeedLock(false);
		setResult(((IBEContext)getBEContext()).getBizEntity().retrieveChild(nodeCodes, idList, tempVar).getData());
	}


	@Override
	protected IBEActionAssembler getAssembler()
	{
		return GetAssemblerFactory().getRetrieveDefaultChildActionAssembler((IBEContext)getBEContext(), nodeCodes, hierachyIdList);
	}


	private String getColumnId(){
		EntityResInfo resInfo;
		//todo 临时处理，
		try {
			resInfo=this.getBEContext().getModelResInfo().getCustomResource(nodeCodes.get(nodeCodes.size()-1));
		}catch (Exception e){
			return  UUID.randomUUID().toString();
		}
		if(resInfo==null)
			return  UUID.randomUUID().toString();
		if(!(resInfo instanceof BefEntityResInfoImpl))
			return UUID.randomUUID().toString();
		ColumnGenerateInfo columnGenerateInfo=((BefEntityResInfoImpl)resInfo).getColumnGenerateInfo();
		return ColumnGenerateConfigLoader.getId(columnGenerateInfo);
	}
}
